#include "../src/shopScheduler.hh"
/**
 * \file shopScheduler.cc
 * \author Jiri Cigler
 * \brief Definition of sorting functions and method of ShopScheduler.
 * \see ShopScheduler 
 */
bool DescendingProcessingTimeSort(const Task& a,const Task& b)
     {
          return a.processingTime  > b.processingTime;
     }

bool AscendingResourceSort(const Task& a, const Task& b)
     {
          return a.processor < b.processor;
     }

bool DescendingNumberOfPrerequirementsSort( const Task& a,const Task& b)
     {
          return a.prerequirements.size() > b.prerequirements.size();
     }
bool ComplexSort( const Task& a,const Task& b)
     {
          return (a.prerequirements.size()+a.processingTime)/(a.processor+1) < (b.prerequirements.size()+b.processingTime)/(b.processor+1);
     }
bool(*sortFunctPtr[])(const Task &a, const Task &b) = {
			DescendingProcessingTimeSort,
			AscendingResourceSort,
			ComplexSort,
			DescendingNumberOfPrerequirementsSort,
};
const unsigned int sortFunctPtrSize = 4;


void ShopScheduler::reindex(int iSortFunc){
	//sort 
	std::sort(taskList.begin(), taskList.end(), *sortFunctPtr[iSortFunc%sortFunctPtrSize]);
	std::vector<SortTableElement> sortTableTmp;
	unsigned int i=0;
	for(std::vector<Task>::iterator it = taskList.begin(); it!= taskList.end(); it++){
		sortTableTmp.push_back(SortTableElement(it->id,i));
		it->id = i;
		i++;
	};
	std::sort(sortTableTmp.begin(), sortTableTmp.end());
	for(std::vector<Task>::iterator it = taskList.begin(); it!= taskList.end(); it++){
		for(std::vector<unsigned int>::iterator it1 = it->prerequirements.begin(); it1!=it->prerequirements.end(); it1++){
			*it1 = sortTableTmp.at(*it1).actual;
		};
	};	
	if(iSortFunc == 0){
		for(i=0; i < sortTableTmp.size();i++){
			sortTable.push_back(sortTableTmp.at(i));
		};
	}
	else{
		for(i=0; i < sortTable.size();i++){
			for(unsigned int j=0; j < sortTableTmp.size();j++){
				if(sortTableTmp[j].previous== sortTable[i].actual){
					sortTable[i].actual = sortTableTmp[j].actual;
					break;
				}
			}
		}
	}
};


void ShopScheduler::init(ShopType shopType, int **& processor, unsigned int **& processingTime, int iJobs, int iTasksInJob){
	taskList.clear();
	sortTable.clear();
	int res, pt,i,j, id;
	id =0;
	//fill in list of activities
	for( i=0; i < iJobs; i++ ){
		for(j = 0; j < iTasksInJob; j++){

			switch(shopType){
				case ST_JOBSHOP:
					res = processor[i][j];
					pt = processingTime[i][j];
					taskList.push_back(Task(pt,res,id++));
					if(j)
						(taskList.end()-1)->prerequirements.push_back((taskList.begin()+(i*iTasksInJob+j-1))->id);
					break;
				case ST_FLOWSHOP:
					pt = processingTime[i][j];
					res = j;
					taskList.push_back(Task(pt,res,id++));
					if(j)
						(taskList.end()-1)->prerequirements.push_back((taskList.begin()+(i*iTasksInJob+j-1))->id);
					break;
				case ST_OPENSHOP:
					res = processor[i][j];
					pt = processingTime[i][j];
					taskList.push_back(Task(pt,res,id++));
					break;
			}
		};
	};

	//Setting up last task	
	taskList.push_back(Task(0,0,taskList.size()));
	for(int i = 1 ; i <= iJobs; i++)
		taskList.at(taskList.size()-1).prerequirements.push_back(taskList.at(i*iTasksInJob -1).id);
	reindex(0);
};
unsigned int ShopScheduler::getMinTime(int **&processor, unsigned int **& processingTime, int jobs, int tasksInJob , int processors){
	unsigned int minTime = 0;
	unsigned int t = 0;
	for(int i=0; i < jobs ; ++i){
		t = 0;
		for(int j = 0; j <tasksInJob;++j){
			t+=processingTime[i][j];	
		};
		if(t > minTime)
			minTime = t;		
	};
	if(processor == NULL )
		return minTime;
	for(int i = 0; i <=processors ; i++){
		t = 0;
		for(int a =0; a < jobs; a++)
			for(int b=0; b < tasksInJob; b++)
				if(processor[a][b]==i)
					t+=processor[a][b];
		if(t>minTime)
			minTime=t;
	};
	return minTime;

}

unsigned int ShopScheduler::getMaxTime(unsigned int **&processingTime, int jobs, int tasksInJob){
	unsigned int maxTime = 0;
	for(int i=0; i < jobs ; ++i){
		for(int j = 0; j <tasksInJob;++j){
			maxTime+=processingTime[i][j];	
		}
	};
	return maxTime;
}
void ShopScheduler::run(ShopType shopType, int **& processor, unsigned int **& processingTime, const
		 int jobs, int tasksInJob, int processors
		 , unsigned int **& result,double * runtime) {

	init(shopType, processor,processingTime,jobs, tasksInJob);
	unsigned int minTime = getMinTime(processor,processingTime,jobs,tasksInJob,processors);

	unsigned int c_d = Search::Config::c_d;
	c_d = 1;
	unsigned int a_d = Search::Config::a_d;
	a_d = 50;

	unsigned int iteration = 0;
	int fails= -1;
	//int time = -1;
	int time = 1000*jobs*tasksInJob;
	bool solution = false;
	try {
		Timer t;
		ShopSolver *s, *ex;
		t.start();
		bool overlap = false;
		while(!solution){
//			if(!overlap){//cout << "\n minTime = " << minTime << "\n"<< endl;*/}
			if(overlap){
				(--minTime);				
				///printf("\n overlapped, iterace: %d , minTime %d\n",iteration+1,minTime);
				reindex(++iteration);
				overlap = false;
				time += jobs*tasksInJob*iteration * 1000;
			}

			s = new ShopSolver(jobs, tasksInJob, processors, minTime++, taskList);

			unsigned int n_p = 0;
			unsigned int n_b = 0;

			if (s->status() != SS_FAILED) {
				n_p = s->propagators();
				n_b = s->branchings();
			}

			Search::Stop* stop = FailTimeStop::create(fails, time);
			//Search::Stop* stop = FailTimeStop::create(-1,-1);
			DFS<ShopSolver> e(s,c_d,a_d,stop);

		//	BAB<ShopSolver> e(s,c_d,a_d,stop);
			//LDS<ShopSolver> e(s,Search::Config::c_d,stop);

			delete s;
			ex = e.next();
			if(e.stopped()){
				overlap=true;
			}else{
				overlap = false;
			}
			if(ex!=NULL){
				solution = true;
				if(verbose)
					ex->print();
				ex->result(result,sortTable, false);
				delete ex;
			}
			if(solution){
				*runtime = t.stop();
				//printf("\nruntime %f\n",*runtime); 	
			}
		}
	} catch (Exception e) {
		cout << "Exception: " << e.what() << "." << endl
			<< "Stopping..." << endl;
	}
	taskList.clear();
	sortTable.clear();
};
ShopScheduler::ShopScheduler(bool v){
	verbose = v;
};

int main(int argc, char ** argv){
	double rtime;
	int size = 6;
	int **res;
	int jobs  = 3;
	int tasksInJob = 2;

	res = new int*[jobs];
	for( int x = 0; x < jobs ; x++ )
		res[x] = new int[tasksInJob];
	
	unsigned int ** dur;
	dur = new unsigned int*[jobs];
	for( int x = 0; x < jobs; x++ )
		dur[x] = new unsigned int[tasksInJob];
	res[0][0]=1; res[0][1]=2;//res[0][2]=2; 
	res[1][0]=2; res[1][1]=2; //res[1][2]=2;
	res[2][0]=2; res[2][1]=1; 
	dur[0][0]=1; dur[0][1]=1;// dur[0][2]=3;
	dur[1][0]=1; dur[1][1]=1;// dur[1][2]=2;
	dur[2][0]=1; dur[2][1]=1; 


/*
	dur[0][0]=1;dur[0][1]=3; dur[0][2]=6; dur[0][3]=7; dur[0][4]=3;dur[0][5]=6;
	dur[1][0]=8;dur[1][1]=5; dur[1][2]=10;dur [1][3]=10;dur[1][4]=10;dur[1][5]=4;
	dur[2][0]=5;dur[2][1]=4; dur[2][2]=8; dur [2][3]=9;dur[2][4]=1;dur[2][5]=7;
	dur[3][0]=5;dur[3][1]=5; dur[3][2]=5; dur [3][3]=3;dur[3][4]=8;dur[3][5]=9;
	dur[4][0]=9;dur[4][1]=3; dur[4][2]=5; dur [4][3]=4;dur[4][4]=3;dur[4][5]=1;
	dur[5][0]=3;dur[5][1]=3; dur[5][2]=9; dur [5][3]=10;dur[5][4]=4;dur[5][5]=1;
	
	res[0][0]=3;res[0][1]=1; res [0][2]=2; res[0][3]=4; res[0][4]=6; res[0][5]=5;
	res[1][0]=2;res[1][1]=3; res [1][2]=5; res[1][3]=6;res[1][4]=1;res[1][5]=4;
	res[2][0]=3;res[2][1]=4; res [2][2]=6; res[2][3]=1;res[2][4]=2;res[2][5]=5;
	res[3][0]=2;res[3][1]=1; res [3][2]=3; res[3][3]=4;res[3][4]=5;res[3][5]=6;
	res[4][0]=3;res[4][1]=2; res [4][2]=5; res[4][3]=6;res[4][4]=1;res[4][5]=4;
	res[5][0]=2;res[5][1]=4; res [5][2]=6; res[5][3]=1;res[5][4]=5;res[5][5]=3;
*/	
	for(int i=0; i < jobs; i++){
		for(int j =0 ; j< tasksInJob; j++)
			 res[i][j] = res[i][j]-1;
	}


	unsigned int **r;
	r = new unsigned int*[jobs];
	for( int x = 0; x < jobs; x++ )
		r[x] = new unsigned int[tasksInJob];


	ShopScheduler *s = new ShopScheduler(/*verbose*/false);

	int ** x = NULL;
	//s->run(ST_FLOWSHOP,x ,dur,size,size,size,r,&rtime);
	//s->run(ST_FLOWSHOP, x ,dur,jobs,tasksInJob,tasksInJob,r,&rtime);
	s->run(ST_OPENSHOP,res ,dur,jobs,tasksInJob,tasksInJob,r,&rtime);
	printf("\nSchedule for input parameters:\n   processors\n");
	for(int i=0; i < jobs; i++){
		for(int j =0 ; j< tasksInJob; j++){
			std::cout << res[i][j] << " ";
	}
		std::cout <<  " " <<std::endl;
	}
	printf("   processing time\n");
	for(int i=0; i < jobs; i++){
		for(int j =0 ; j< tasksInJob; j++){
			std::cout << dur[i][j] << " ";
	}
		std::cout <<  " " <<std::endl;
	}



	std::cout <<  "  start time \n " <<std::endl;
	for(int i=0; i < jobs; i++){
		for(int j =0 ; j< tasksInJob; j++){
			std::cout << r[i][j] << " ";
	}
		std::cout <<  " " <<std::endl;
	}

/*	std::cout <<  "\n Duration: \n " <<std::endl;
	for(int i=0; i < size; i++){
		for(int j =0 ; j< size; j++){
			std::cout << dur[i][j] << " ";
		}
		std::cout <<  " " <<std::endl;
	}
	
	std::cout <<  "\n Resource: \n " <<std::endl;
	for(int i=0; i < size; i++){
		for(int j =0 ; j< size; j++){
			std::cout << res[i][j] << " ";
		}
		std::cout <<  " " <<std::endl;
	}
*/		
	//TODO better cleanup
	delete res;
	delete dur;
	delete r;
/*
	int **res;
	res = new int*[4];
	for( int x = 0; x < 4; x++ )
		res[x] = new int[4];
	unsigned int ** dur;
	dur = new unsigned int*[4];
	for( int x = 0; x < 4; x++ )
		dur[x] = new unsigned int[4];
	dur[0][0]=1;dur[0][1]=3; dur[0][2]=6; dur[0][3]=7;
	dur[1][0]=8;dur[1][1]=5; dur[1][2]=10;dur [1][3]=10;
	dur[2][0]=5;dur[2][1]=4; dur[2][2]=8; dur [2][3]=9;
	dur[3][0]=5;dur[3][1]=5; dur[3][2]=5; dur [3][3]=3;
	
	res[0][0]=3;res[0][1]=1; res[0][2]=2; res[0][3]=4;
	res[1][0]=1;res[1][1]=3; res [1][2]=4; res[1][3]=3;
	res[2][0]=3;res[2][1]=4; res[2][2]=2; res[2][3]=1;
	res[3][0]=2;res[3][1]=1; res [3][2]=3; res[3][3]=4;

	unsigned int **r;
	r = new unsigned int*[4];//tasksinjob
	for( int x = 0; x < 4; x++ )
		r[x] = new unsigned int[4];//jobs

	run(res,dur,opt,4,4,4,100,r);
	for(int i=0; i < 4; i++){
		for(int j =0 ; j< 4; j++){
			std::cout << r[i][j] << " ";
		}
		std::cout <<  " " <<std::endl;
	}
		
	//TODO better cleanup
	delete res;
	delete dur;
	delete r;
	*/
}


